#include<iostream>
#include<string>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/time.h>
#include<unistd.h>

#include"Sock.hpp"
#include"log.hpp"
#include"err.hpp"

const static uint16_t defaultport=8888;
const static int N=sizeof(fd_set)*8;
const static int defaultfd=-1;
typedef int type_t;

class SelectServer
{
public:
    SelectServer(uint16_t port=defaultport):_port(port)
    {}

    void InitServer()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        for(int i=0;i<N;++i)
            fdarray[i]=defaultfd;
    }

    void Accept()
    {
        std::string clientIp;
        uint16_t clientPort;
        int sock=_listensock.Accept(&clientIp,&clientPort);
        std::string name="["+clientIp+":"+std::to_string(clientPort)+"]";
        if(sock<0)
            return;
        int i=1;
        for(;i<N;++i)
        {
            if(fdarray[i]!=defaultfd)
                continue;
            fdarray[i]=sock;
            logMessage(Info,"%s连接到来,sock:%d",name.c_str(),sock);
            break;
        }
        if(i>=N)
        {
            std::string echo="连接已满,请稍后尝试";
            send(sock,echo.c_str(),echo.size(),0);
            close(sock);
        }
    }

    void HandlerEvent(fd_set&rfds)
    {
        for(int i=0;i<N;++i)
        {
            if(fdarray[i]==defaultfd)
                continue;
            //连接事件到来
            if(fdarray[i]==_listensock.Fd() && FD_ISSET(fdarray[i],&rfds))
                Accept();
            else if(fdarray[i]!=_listensock.Fd() && FD_ISSET(fdarray[i],&rfds))
            {
                char buffer[1024];
                int n=recv(fdarray[i],buffer,sizeof(buffer)-1,0);
                if(n<0)
                    logMessage(Warning,"recv error,%d:%s",errno,strerror(errno));
                else if(n>0)
                {
                    buffer[n]='\0';
                    std::cout<<"client# "<<buffer<<std::endl;
                    //返回响应
                    std::string echo="[server echo] ";
                    echo+=buffer;
                    send(fdarray[i],echo.c_str(),echo.size(),0);
                }
                else
                {
                    //客户端关闭连接
                    logMessage(Info,"client quit...%d",fdarray[i]);
                    close(fdarray[i]);
                    fdarray[i]=defaultfd;
                }
            }
        }
    }

    void Start()
    {
        fdarray[0]=_listensock.Fd();
        while(true)
        {
            fd_set rfds;//读事件集
            FD_ZERO(&rfds);
            int maxfd=fdarray[0];
            //设置需要关心的读事件
            for(int i=0;i<N;++i)
            {
                if(fdarray[i]==defaultfd)
                    continue;
                FD_SET(fdarray[i],&rfds);
                //获取最大的fd
                if(fdarray[i]>maxfd)
                    maxfd=fdarray[i];
            }
            //最后时间NULL，代表阻塞式等待
            int n=select(maxfd+1,&rfds,nullptr,nullptr,nullptr);
            switch(n)
            {
                case 0:
                    logMessage(Info,"timeout...%d:%s",errno,strerror(errno));
                    break;
                case -1:
                    logMessage(Warning,"select error,&d:%s",errno,strerror(errno));
                    break;
                default:
                    //有连接到来
                    HandlerEvent(rfds);
                    continue;
            }
        }
    }

    ~SelectServer()
    {}
private:
    uint16_t _port;//端口号
    Sock _listensock;//监听套接字
    type_t fdarray[N];//连接套接字管理数组
};